/**
 * 
 */
package connection;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

import exception.ApplicationException;

import exception.ModelException;
import serialization.SerializationUtils;

/**
 * Creation date: Nov 15, 2007
 * Use case: 
 *
 * @author: cristian.rasch
 */
public class ConnectionManager {
    
    private final static int maxRetries = 3;
    
    private HttpConnection conn = null;
    private InputStream is = null;
    private OutputStream os = null;
    private String url = null;

    public ConnectionManager(String url) {
        this.url = url;
    }
    
    public void execute(byte operation, Object[] params) throws ApplicationException, ModelException {
    	connect(operation, params);
    }

    public DataInput openIOConnection(byte operation, Object[] params) throws ApplicationException, ModelException {
        return  connect(operation, params);
    }

    private DataInput connect(byte operation, Object[] params) throws ApplicationException, ModelException {
    	int i=0;
    	boolean done = false;
    	boolean threwException = false;
    	Exception e = null;
    	DataInput in = null;

    	do {
    		try {
    			openConnection(operation);
                os.write(params.length); // the number of params we are sending
                for(int j = 0; j < params.length; j++)
                    os.write(SerializationUtils.serialize(params[j]));
    			in = readResponse();
    			closeConnection();
    			threwException = false;
    			done = true;
    		} catch(IOException ioe) {
    			threwException = true;
    			e = ioe;
    		}
    	}
    	while(i < maxRetries && !done);

    	if(threwException)
    		throw new ApplicationException(ApplicationException.HTTP_IO_EXCEPTION, e);
    	else
    		return in;
    }

    private void openConnection(byte operation) throws IOException {
        conn = (HttpConnection)Connector.open(url);
        os = conn.openOutputStream();
        os.write(operation);
    }
        
    private DataInput readResponse() throws IOException, ApplicationException, ModelException {
    	is = conn.openInputStream();
        byte status = (byte)is.read();

        if(status == constants.ConnConstants.SUCCESS) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b;
            while((b = is.read()) != -1) {
                baos.write(b);
            }
            return new DataInputStream(new ByteArrayInputStream(baos.toByteArray()));
        } else {
            DataInputStream dis = new DataInputStream(is);
            byte code = dis.readByte();
            if(status == constants.ConnConstants.APPLICATION_EXCEPTION) {
                throw new ApplicationException(code);
            } else {
                throw new ModelException(code);
            }
        }
    }
    
    private void closeConnection() throws IOException {
        if(is != null)
        	is.close();
        if(os != null)
        	os.close();
        if(conn != null)
        	conn.close();
    }
    
}
